package ${domain}.module.wsys.mgr;

import ${domain}.frame.auth.LocalData;
import ${domain}.frame.auth.Token;
import ${domain}.frame.base.ErrorType;
import ${domain}.frame.utils.IDgenerator;
import ${domain}.frame.utils.MD5Util;
import ${domain}.frame.utils.MapperUtil;
import ${domain}.frame.utils.Message;
import ${domain}.frame.utils.RequestUtil;
import ${domain}.frame.utils.ValidationUtil;
import ${domain}.module.wsys.ent.Dept;
import ${domain}.module.wsys.ent.Role;
import ${domain}.module.wsys.ent.User;
import ${domain}.module.wsys.mpr.UserMapper;
import ${domain}.module.wsys.req.DeptFindRequest;
import ${domain}.module.wsys.req.RoleFindRequest;
import ${domain}.module.wsys.req.TokensCreateRequest;
import ${domain}.module.wsys.req.UserChangePwdRequest;
import ${domain}.module.wsys.req.UserResetPwdRequest;
import ${domain}.module.wsys.req.UserCreateRequest;
import ${domain}.module.wsys.req.UserDeleteRequest;
import ${domain}.module.wsys.req.UserFindRequest;
import ${domain}.module.wsys.req.UserLoginRequest;
import ${domain}.module.wsys.req.UserRoleCreateRequest;
import ${domain}.module.wsys.req.UserUpdateRequest;
import ${domain}.module.wsys.rsp.DeptFindResponse;
import ${domain}.module.wsys.rsp.RoleFindResponse;
import ${domain}.module.wsys.rsp.TokensCreateResponse;
import ${domain}.module.wsys.rsp.UserChangePwdResponse;
import ${domain}.module.wsys.rsp.UserResetPwdResponse;
import ${domain}.module.wsys.rsp.UserCreateResponse;
import ${domain}.module.wsys.rsp.UserDeleteResponse;
import ${domain}.module.wsys.rsp.UserFindResponse;
import ${domain}.module.wsys.rsp.UserLoginResponse;
import ${domain}.module.wsys.rsp.UserRoleCreateResponse;
import ${domain}.module.wsys.rsp.UserUpdateResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

/**
 * USER - 用户
 *
 * @author wangbing
 * @version 0.0.1
 * @since 2017-01-01
 */
@Transactional
@Service
public class UserManagerImpl implements UserManager {

    @Value("${r'${web.url.auth.admin}'}")
    private String admin;
    @Value("${r'${web.url.auth.pwd}'}")
    private String pwd;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TokensManager tokensManager;
    @Autowired
    private DeptManager deptManager;
    @Autowired
    private RoleManager roleManager;
    @Autowired
    private UserRoleManager userRoleManager;
    @Autowired
    private ProfilesManager profilesManager;

    /**
     * 插入
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    public UserCreateResponse create(UserCreateRequest request, Token token) {
        UserCreateResponse response = new UserCreateResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        long id = IDgenerator.nextId();
        User entity = MapperUtil.map(request, User.class);
        entity.setId(id);
        entity.setUserPwd(MD5Util.generatePwd(entity.getUserPwd()));

        {// 检查是否与设置的超级管理员账户相同
            String admin = LocalData.getEnvironment().getProperty("web.url.auth.admin", "admin");
            if (admin.equals(request.getUserName())) {
                response.addError(ErrorType.BUSINESS_ERROR, "[" + request.getUserName() + "]用户名已被超级管理员占用");
                return response;
            }
        }

        if (StringUtil.isNotEmpty(request.getDeptCode())) {// 检查机构设置是否正确
            DeptFindRequest deptFindRequest = new DeptFindRequest();
            deptFindRequest.setDeptCode(request.getDeptCode());
            deptFindRequest.setPageSize(1);
            DeptFindResponse deptFindResponse = deptManager.find(deptFindRequest, token);
            if (deptFindResponse.hasError()) {
                response.addErrors(deptFindResponse.getErrors());
                return response;
            }
            if (deptFindResponse.getResult().size() == 0) {
                response.addError(ErrorType.BUSINESS_ERROR, "[" + request.getDeptCode() + "]机构代码不存在");
                return response;
            }
            Dept dept = deptFindResponse.getResult().get(0);
            entity.setDeptId(dept.getId());
            entity.setDeptName(dept.getDeptName());
        }

        long result = userMapper.insert(entity, token);
        if (1L != result) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.CREATE_FAILURE);
            return response;
        }

        // 检查角色设置是否正确
        for (String code : request.getRoleCodeList()) {
            RoleFindRequest roleFindRequest = new RoleFindRequest();
            roleFindRequest.setCode(code);
            RoleFindResponse roleFindResponse = roleManager.find(roleFindRequest, token);
            if (roleFindResponse.hasError()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                response.addErrors(roleFindResponse.getErrors());
                return response;
            } else if (roleFindResponse.getResult().size() == 0) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                response.addError(ErrorType.BUSINESS_ERROR, "[" + code + "]角色代码不存在!");
                return response;
            }

            Role role = roleFindResponse.getResult().get(0);
            UserRoleCreateRequest userRoleCreateRequest = new UserRoleCreateRequest();
            userRoleCreateRequest.setUserId(id);
            userRoleCreateRequest.setUserCode(request.getUserCode());
            userRoleCreateRequest.setRoleId(role.getId());
            userRoleCreateRequest.setRoleCode(role.getCode());
            UserRoleCreateResponse userRoleCreateResponse = userRoleManager.create(userRoleCreateRequest, token);
            if (userRoleCreateResponse.hasError()) {
                response.addErrors(userRoleCreateResponse.getErrors());
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return response;
            }
        }

        response.setId(id);

        return response;
    }

    /**
     * 逻辑删除
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    public UserDeleteResponse delete(UserDeleteRequest request, Token token) {
        UserDeleteResponse response = new UserDeleteResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        long result = userMapper.delete(request.getId(), token);
        if (1L != result) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.DELETE_FAILURE);
            return response;
        }
        response.setResult(result);

        return response;
    }

    /**
     * 更新
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    public UserUpdateResponse update(UserUpdateRequest request, Token token) {
        UserUpdateResponse response = new UserUpdateResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        User entity = userMapper.getById(request.getId(), token);
        if (entity == null) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.GET_FAILURE);
            return response;
        }

        MapperUtil.map(request, entity);
        long result = userMapper.update(entity, token);
        if (1L != result) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.UPDATE_FAILURE);
            return response;
        }
        response.setResult(result);

        return response;
    }

    /**
     * 更新密码
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    public UserChangePwdResponse changePwd(UserChangePwdRequest request, Token token) {
        UserChangePwdResponse response = new UserChangePwdResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        User entity = userMapper.getById(LocalData.getToken().getUserId(), token);
        if (entity == null) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.GET_FAILURE);
            return response;
        }

        if (!entity.getUserPwd().equals(MD5Util.generatePwd(request.getPassword()))) {
            response.addError(ErrorType.BUSINESS_ERROR, "登录密码错误!");
            return response;
        }
        entity.setUserPwd(MD5Util.generatePwd(request.getNewPassword()));

        MapperUtil.map(request, entity);
        long result = userMapper.changePwd(entity, token);
        if (1L != result) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.UPDATE_FAILURE);
            return response;
        }
        response.setResult(result);

        return response;
    }

    /**
     * 重置密码
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    public UserResetPwdResponse resetPwd(UserResetPwdRequest request, Token token) {
        UserResetPwdResponse response = new UserResetPwdResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        User entity = userMapper.getById(request.getId(), token);
        if (entity == null) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.GET_FAILURE);
            return response;
        }

        // 获取默认密码
        String userDefaultPassword = profilesManager.getString("user.default.password", "123456");
        entity.setUserPwd(MD5Util.generatePwd(userDefaultPassword));
        entity.setRowVersion(request.getRowVersion());

        long result = userMapper.changePwd(entity, token);
        if (1L != result) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.UPDATE_FAILURE);
            return response;
        }
        response.setResult(result);

        return response;
    }

    /**
     * 查询
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    @Transactional(readOnly = true)
    public UserFindResponse find(UserFindRequest request, Token token) {
        UserFindResponse response = new UserFindResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        if (request.getPageSize() != 0) {
            PageHelper.startPage(request.getPageNumber(), request.getPageSize());
        }
        if (StringUtil.isNotEmpty(request.getSortKey())) {
            PageHelper.orderBy(request.getSortKey() + " " + request.getSortType());
        }
        PageInfo<User> pageInfo = new PageInfo<>(userMapper.find(request, token));

        response.setResult(pageInfo.getList());
        response.setTotalCount(pageInfo.getTotal());

        return response;
    }

    @Override
    public UserLoginResponse login(UserLoginRequest request, Token token) {
        UserLoginResponse response = new UserLoginResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        User user = null;
        if (request.getUsername().equals(admin)) {//超级管理员登录
            String generatePwd = MD5Util.generatePwd(request.getPassword());
            if (!generatePwd.equals(pwd)) {
                response.addError(ErrorType.BUSINESS_ERROR, "用户名或密码错误!");
            }
            user = new User();
            user.setId(0);
            user.setUserName(admin);
            user.setUserAlias("超级管理员");
        } else {//管理员登录
            UserFindRequest userFindRequest = new UserFindRequest();
            userFindRequest.setUserName(request.getUsername());
            UserFindResponse userFindResponse = this.find(userFindRequest, LocalData.getSysToken());

            if (userFindResponse.hasError()) {
                response.addErrors(userFindResponse.getErrors());
                return response;
            } else if (userFindResponse.getResult().size() == 0) {
                response.addError(ErrorType.BUSINESS_ERROR, "用户名或密码错误!");
                return response;
            } else if (userFindResponse.getResult().size() > 1) {
                response.addError(ErrorType.BUSINESS_ERROR, "用户信息异常!");
                return response;
            }

            user = userFindResponse.getResult().get(0);

            String generatePwd = MD5Util.generatePwd(request.getPassword());
            if (!generatePwd.equals(user.getUserPwd())) {
                response.addError(ErrorType.BUSINESS_ERROR, "用户名或密码错误!");
                return response;
            }
        }

        if (!response.hasError()) {// 创建Token
            Date current = new Date();
            Calendar instance = Calendar.getInstance();
            instance.setTime(current);
            instance.add(Calendar.HOUR_OF_DAY, 3);//默认一个小时内有效

            TokensCreateRequest tokensCreateRequest = new TokensCreateRequest();
            tokensCreateRequest.setToken(UUID.randomUUID().toString());
            tokensCreateRequest.setUserId(user.getId());
            tokensCreateRequest.setUserName(user.getUserName());
            tokensCreateRequest.setUserAlias(user.getUserAlias());
            tokensCreateRequest.setDeptId(user.getDeptId());
            tokensCreateRequest.setDeptCode(user.getDeptCode());
            tokensCreateRequest.setDeptName(user.getDeptName());
            tokensCreateRequest.setLoginTime(current);
            tokensCreateRequest.setValidTime(instance.getTime());
            tokensCreateRequest.setValid(true);
            tokensCreateRequest.setTerminal("WEB");
            tokensCreateRequest.setTerminalIp(RequestUtil.getIp(LocalData.getRequest()));
            tokensCreateRequest.setTerminalInfo(RequestUtil.getUserAgent(LocalData.getRequest()));
            TokensCreateResponse tokensCreateResponse = tokensManager.create(tokensCreateRequest, LocalData.getSysToken());

            if (tokensCreateResponse.hasError()) {
                response.addErrors(tokensCreateResponse.getErrors());
                return response;
            }
            response.setToken(tokensCreateRequest.getToken());
        }

        return response;
    }
}
